﻿package zf.data.tools
{
	/**
	 * 农历类 1900-2100之间有效，请注意，阳历月份(Date)是从0-11取值的
	 * @author mike.zhang
	 * 
	 */
	public class LunarDate
	{
		private var _year:Number;
		private var _month:Number;
		private var _date:Number;
		private var _animal:int;
		
		private var pdate:Date;

		private static  var lunarInfo:Array = new Array("19416", "19168", "42352", "21717", "53856", "55632", "21844", "22191", "39632", "21970", "19168", "42422", "42192", "53840", "53909", "46415", "54944", "44450", "38320", "18807", "18815", "42160", "46261", "27216", "27968", "43860", "11119", "38256", "21234", "18800", "25958", "54432", "59984", "27285", "23263", "11104", "34531", "37615", "51415", "51551", "54432", "55462", "46431", "22176", "42420", "9695", "37584", "53938", "43344", "46423", "27808", "46416", "21333", "19887", "42416", "17779", "21183", "43432", "59728", "27296", "44710", "43856", "19296", "43748", "42352", "21088", "62051", "55632", "23383", "22176", "38608", "19925", "19152", "42192", "54484", "53840", "54616", "46400", "46752", "38310", "38335", "18864", "43380", "42160", "45690", "27216", "27968", "44870", "43872", "38256", "19189", "18800", "25776", "29859", "59984", "27480", "23232", "43872", "38613", "37600", "51552", "55636", "54432", "55888", "30034", "22176", "43959", "9680", "37584", "51893", "43344", "46240", "47780", "44368", "21977", "19360", "42416", "20854", "21183", "43312", "31060", "27296", "44368", "23378", "19296", "42726", "42208", "53856", "60005", "54576", "23200", "30371", "38608", "19195", "19152", "42192", "53430", "53855", "54560", "56645", "46496", "22224", "21938", "18864", "42359", "42160", "43600", "45653", "27951", "44448", "19299", "37759", "18936", "18800", "25776", "26790", "59999", "27424", "42692", "43759", "37600", "53987", "51552", "54615", "54432", "55888", "23893", "22176", "42704", "21972", "21200", "43448", "43344", "46240", "46758", "44368", "21920", "43940", "42416", "21168", "45683", "26928", "29495", "27296", "44368", "19285", "19311", "42352", "21732", "53856", "59752", "54560", "55968", "27302", "22239", "19168", "43476", "42192", "53584", "62034", "54560");
		//private static var Animals:Array=new Array(1,2,3,4,5,6,7,8,9,10,11,12);

		private static  var animalString1:Array=new Array("子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥");
		private static  var animalString2:Array=new Array("鼠","牛","虎","兔","龙","蛇","马","羊","猴","鸡","狗","猪");

		private static  var gan:Array=new Array("甲","乙","丙","丁","戊","己","庚","辛","壬","癸");
		private static  var zhi:Array=new Array("子","丑","寅","卯","辰","巳","午","未","申","酉","戌","亥");

		private static  var lunarDate:Array=new Array("一","二","三","四","五","六","七","八","九","十");

		private static  var sTermInfo:Array = new Array(0, 21208, 42467, 63836, 85337, 107014, 128867, 150921, 173149, 195551, 218072, 240693, 263343, 285989, 308563, 331033, 353350, 375494, 397447, 419210, 440795, 462224, 483532, 504758);
		private static  var sTerm:Array = new Array("小寒","大寒","立春","雨水","惊蛰","春分","清明","谷雨","立夏","小满","芒种","夏至","小暑","大暑","立秋","处暑","白露","秋分","寒露","霜降","立冬","小雪","大雪","冬至");
		//s1   =   "甲乙丙丁戊己庚辛壬癸"   
		//s2   =   "子丑寅卯辰巳午未申酉戌亥"   
		//s3   =   "鼠牛虎兔龙蛇马羊猴鸡狗猪"   
		//s4   =   "小寒大寒立春雨水惊蛰春分清明谷雨立夏小满芒种夏至小暑大暑立秋处暑白露秋分寒露霜降立冬小雪大雪冬至"  
		
		private static var jcNamejx:Array = new Array("宜:出行,上任,会友,上书,见工\n忌:动土,开仓,嫁娶,纳采", "宜:除服,疗病,出行,拆卸,入宅\n忌:求官,上任,开张,搬家,探病", "宜:祈福,祭祀,结亲,开市,交易\n忌:服药,求医,栽种,动土,迁移", "宜:祭祀,修墳,涂泥,餘事勿取\n忌:移徙.入宅.嫁娶.开市.安葬", "宜:交易,立券,会友,签約,納畜\n忌:种植,置业,卖田,掘井,造船", "宜:祈福,祭祀,求子,结婚,立约\n忌:开市,交易,搬家,远行 ", "宜:求医,赴考,祭祀,餘事勿取\n忌:动土,出行,移徙,开市,修造", "宜:经营,交易,求官,納畜,動土\n忌:登高,行船.安床.入宅.博彩", "宜:祈福,入学,开市,求医,成服\n忌:词讼,安門,移徙", "宜:祭祀,求财,签约,嫁娶,订盟\n忌:开市.安床.安葬.入宅.破土", "宜:疗病,结婚,交易,入仓,求职\n忌:安葬,动土,针灸", "宜:祭祀,交易,收财,安葬\n忌:宴会,安床,出行,嫁娶,移徙");
		private static var jcName:Array = new Array(0, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1);
		
		public function LunarDate (d:Date)
		{
			pdate=d;
			Lunar (d);
			_animal=(_year-1900) %12;
		}
		public function get date ():Number
		{
			return _date;
		}

		public function get month ():Number
		{
			return _month;
		}

		public function get year ():Number
		{
			return _year;
		}
		/**
		 * 返回生肖编号，0-11取值
		 * @return 
		 * 
		 */
		public function get animal ():int
		{
			return _animal;
		}
		/**
		 * 获得农历月 
		 * @return 农历月,如“一月”
		 * 
		 */
		public function getLunarMonth ():String
		{
			var s:String;

			if (_month<=10)
			{
				s=lunarDate[_month-1];
			}
			else
			{
				s="十"+lunarDate[_month%10-1];
			}
			return s + "月";
		}
		/**
		 * y年的第n个节气（从小寒开始）对应的时间 
		 * @param y 年份
		 * @param n 节气编号，从小寒开始
		 * @return 日期Date
		 * 
		 */
		private function getSTermDate (y:Number, n:Number):Date
		{
			trace(3.155693E+010 * (y - 1900) + sTermInfo[n] * 60000 + Date.UTC(1900, 0, 6, 2, 5));
			var d:Date = new Date(3.155693E+010 * (y - 1900) + sTermInfo[n] * 60000 + Date.UTC(1900, 0, 6, 2, 5));
			trace(d.getFullYear());
			d.setDate (d.getUTCDate());
			return d;
		}
		/**
		 * 测试年份的节气
		 * 
		 */
		public function testSTrem ():void
		{
			var d:Date;
			for (var i:Number=0; i<sTerm.length; i++)
			{
				d=getSTermDate(_year,i);
				trace (sTerm[i]+":"+d.getFullYear()+"-"+Number(d.getMonth()+1)+"-"+d.getDate());
			}
		}
		/**
		 * 获得农历日 
		 * @return 农历日，如“廿十”
		 * 
		 */
		public function getLunarDate ():String
		{
			var s:String;
			var num:Number=_date%10-1;
			if (_date<=10)
			{
				s="初"+lunarDate[_date-1];
			}
			else if (_date<20)
			{
				s="十"+lunarDate[num];
			}
			else if (_date==20)
			{
				s="廿十";
			}
			else if (_date<30)
			{
				s="廿"+lunarDate[num];
			}
			else
			{
				s="卅十";
			}
			return s;
		}
		/**
		 * 将年份用天干地支表示 
		 * @return 天干地支
		 * 
		 */
		public function getChinaEra ():String
		{
			var strGan:String=gan[(_year-1900+6)%10];
			var strZhi:String=zhi[(_year-1900+12)%12];

			return strGan + strZhi + "年";
		}
		/**
		 * 获得生肖，例如：鼠 
		 * @return 生肖
		 * 
		 */
		public function getAnimal ():String
		{
			return animalString2[_animal];
			//return animalString1[_animal]+animalString2[_animal];
		}
		/*
		private function CalConv2(yy, mm, dd, y, d, m, dt, nm, nd):String
		{
			var _loc4 = d + "" + dd;
			if (yy == 0 && dd == 6 || yy == 6 && dd == 0 || yy == 1 && dd == 7 || yy == 7 && dd == 1 || yy == 2 && dd == 8 || yy == 8 && dd == 2 || yy == 3 && dd == 9 || yy == 9 && dd == 3 || yy == 4 && dd == 10 || yy == 10 && dd == 4 || yy == 5 && dd == 11 || yy == 11 && dd == 5)
			{
				return ("日值岁破 大事不宜");
			}
			else if (mm == 0 && dd == 6 || mm == 6 && dd == 0 || mm == 1 && dd == 7 || mm == 7 && dd == 1 || mm == 2 && dd == 8 || mm == 8 && dd == 2 || mm == 3 && dd == 9 || mm == 9 && dd == 3 || mm == 4 && dd == 10 || mm == 10 && dd == 4 || mm == 5 && dd == 11 || mm == 11 && dd == 5)
			{
				return ("日值月破 大事不宜");
			}
			else if (y == 0 && _loc4 == "911" || y == 1 && _loc4 == "55" || y == 2 && _loc4 == "111" || y == 3 && _loc4 == "75" || y == 4 && _loc4 == "311" || y == 5 && _loc4 == "95" || y == 6 && _loc4 == "511" || y == 7 && _loc4 == "15" || y == 8 && _loc4 == "711" || y == 9 && _loc4 == "35")
			{
				return ("日值上朔 大事不宜");
			}
			else if (m == 7 && dt == 7 || nm == "8" && nd == "4")
			{
				return ("日值母亲忌 大事不宜");
			}
			else if (m == 1 && dt == 13 || m == 2 && dt == 11 || m == 3 && dt == 9 || m == 4 && dt == 7 || m == 5 && dt == 5 || m == 6 && dt == 3 || m == 7 && dt == 1 || m == 7 && dt == 29 || m == 8 && dt == 27 || m == 9 && dt == 25 || m == 10 && dt == 23 || m == 11 && dt == 21 || m == 12 && dt == 19)
			{
				return ("日值杨公十三忌 大事不宜");
			}
			else
			{
				return "0";
			}
		}
		**
		 * 获得当日的适宜禁忌，有BUG，某些相差1-2天 
		 * @return 文字
		 * 
		 *
		public function getTaboo():String
		{

			
			var y:Number=pdate.getFullYear();
			var m:Number=pdate.getMonth();
			var _loc22:Number = Date.UTC(y, m, 1, 0, 0, 0, 0) / 86400000 + 25567 + 10;
			var _loc7:Number=pdate.date-1;
			
			var _loc14:Number = (y - 1900) * 12 + m + 12;
			var _loc34 = getSTermDate(y,m*2).date-1;
			
			var _loc18;
			var _loc6 = _loc22 + _loc7;
			var _loc4 = _loc7 + 1;
			if (_loc7 + 1 == _loc34)
			{
				_loc14 = (y - 1900) * 12 + m + 13;
			}
			if (m < 2)
			{
				_loc18 = y - 1900 + 36 - 1;
			}
			else
			{
				_loc18 = y - 1900 + 36;
			}
			var sgz5 = CalConv2(_loc18 % 12, _loc14 % 12, _loc6 % 12, _loc18 % 10, _loc6 % 10, _month, date - 1, m + 1, _loc4);
			var sgzjc=jcNamejx[((_loc22 + _loc7) % 12 + jcName[_loc14 % 12]) % 12];
			if(sgz5!="0")
			{
				return sgz5
			}
			return sgzjc;
		}
		
		public function testTaboo():void
		{
			var lunar:LunarDate;
			for(var i:uint=1;i<28;i++)
			{
				lunar=new LunarDate(new Date(pdate.getFullYear(),pdate.getMonth(),i));
				trace(pdate.getFullYear()+"-"+Number(pdate.getMonth()+1)+"-"+i+"  "+lunar.getTaboo());
			}
		}
		*/
		/**
		 * y年的总天数 
		 * @param y 年份
		 * @return 天数
		 * 
		 */
		private function lYearDays (y:Number):Number
		{
			var i:Number;
			var sum:Number = 348;
			for (i = 32768; i > 8; i = i >> 1)
			{
				sum = sum + (lunarInfo[y - 1900] & i ? (1) : (0));
			}
			return (sum + leapDays(y));
		}
		/**
		 * y年闰哪个月   1-12   ,   没闰传回   0 
		 * @param y 年
		 * @return 月份
		 * 
		 */
		private function leapMonth (y:Number):Number
		{
			var lm:Number = lunarInfo[y - 1900] & 15;
			return lm == 15?0:lm;
		}
		/**
		 * y年闰月的天数 
		 * @param y 年份
		 * @return 天数
		 * 
		 */
		private function leapDays (y:Number):Number
		{
			if (leapMonth(y))
			{
				return lunarInfo[y - 1899] & 15 == 15?30:29;
			}
			return 0;
		}
		/**
		 * y年m月的总天数 
		 * @param y 年
		 * @param m 月
		 * @return 天数
		 * 
		 */
		private function monthDays (y:Number, m:Number):Number
		{
			return lunarInfo[y - 1900] & 65536 >> m?30:29;
		}
		/**
		 * 根据阳历日期获得农历日期 
		 * @param objDate 阳历(Date)
		 * 
		 */
		private function Lunar (objDate:Date):void
		{
			var i:Number;
			var leap:Number = 0;
			var temp:Number = 0;

			var isLeap:Boolean=false;

			//var lunarDate:LunarDate=new LunarDate();
			var offset:Number = (Date.UTC(objDate.getFullYear(), objDate.getMonth(), objDate.getDate()) - Date.UTC(1900, 0, 31)) / 86400000;
			for (i = 1900; i < 2100 && offset > 0; i++)
			{
				temp = lYearDays(i);
				offset = offset - temp;
			}
			if (offset < 0)
			{
				offset = offset + temp;
				--i;
			}
			_year = i;
			leap = leapMonth(i);

			for (i = 1; i < 13 && offset > 0; i++)
			{
				if (leap > 0 && i == leap + 1 && isLeap == false)
				{
					--i;
					isLeap = true;
					temp = leapDays(_year);
				}
				else
				{
					temp = monthDays(_year, i);
				}
				if (isLeap == true && i == leap + 1)
				{
					isLeap = false;
				}
				offset = offset - temp;
			}
			if (offset == 0 && leap > 0 && i == leap + 1)
			{
				if (isLeap)
				{
					isLeap = false;
				}
				else
				{
					isLeap = true;
					--i;
				}
			}
			if (offset < 0)
			{
				offset = offset + temp;
				--i;
			}
			_month = i;
			_date = offset + 1;
			//return lunarDate;
		}
		
		/**
		 * 利用农历返回阳历，例如 lunarToDate(2010,1,1) 返回 2010-1-14 (注意阳历月份为0-11，此农历为1-12)
		 * @param	year 年
		 * @param	month 月份，1-12
		 * @param	date 日
		 * @return
		 */
		public static function lunarToDate (year:Number, month:Number, date:Number):Date
		{
			var d:Date;
			var lunar:LunarDate;
			var bool:Boolean = true;
			
			for (var i:Number = -1; i < 2 && bool; i++)
			{
				for (var j:Number = 0; j < 12; j++)
				{
					d = new Date (year + i, j, 1);
					lunar = new LunarDate (d);
					//下面注释的方法将返回year年的该农历
					//if (year == d.getFullYear() && month == lunar.month)
					if (year == lunar.year && month == lunar.month)
					{
						bool = false;
						break;
					}
				}
			}
			var num:Number = lunar.date;
			num = num - date;
			
			num = d.getDate () - num;
			d.setDate (num);
			
			return d;
		}
		
		/**
		 * 返回农历，格式 1990-07-05 
		 * @return 
		 * 
		 */
		public function toString ():String
		{
			var mm:String=_month>9?""+_month:"0"+_month;
			var dd:String=_date>9?""+_date:"0"+_date;

			return _year + "-" + mm + "-" + dd;
		}
	}
}